﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using StarTrek.UI.Console.MenuItem;

namespace StarTrek.UI.Console
{
    class MenuContext : ICollection<iMenuItem>
    {
        private readonly int LINE_WIDTH = 40;
        private readonly  string MENU_INDENT= new string(' ',5);
        private List<iMenuItem> menuItems = new List<iMenuItem>();
        private bool terminateApplicaiton = false;
        private string inputAction;
        private readonly iMenuItem defaultChoice;

        public MenuContext(iMenuItem DefaultChoice)
        {
            defaultChoice = DefaultChoice;
        }
        public void DisplayMenu(TextWriter sw)
        {
            sw.WriteLine(Properties.Resources.MenuHeader);
            foreach(iMenuItem i in menuItems)
            {
                sw.WriteLine("{0}{1} - {2}",MENU_INDENT,i.MenuAction,i.Text);
            }
            sw.Write(Properties.Resources.MenuPrompt);
        }

        public void WaitForInput(TextReader tr)
        {
            //ReadLine is a blocking call 
            inputAction = tr.ReadLine();
        }

        public bool DispatchAction(TextWriter sw, TextReader tr)
        {
            bool rVal = false;
            try
            {
                menuItems.ForEach((i) => rVal = rVal || i.ProcessSomeRequest(this, sw, tr));

                //No item was triggered.
                if (!rVal) defaultChoice.ProcessSomeRequest(this, sw, tr);
            }catch(InvalidDataException ex)
            {
                sw.WriteLine(this.wordWrap(ex.Message));
                defaultChoice.ProcessSomeRequest(this, sw, tr);
            }

            return rVal;
        }
        public bool TerminateApplicaiton
        {
            get { return terminateApplicaiton; }
            set { terminateApplicaiton = value; }
        }
        public string wordWrap(string s)
        {
            //implemented greedy wordWraping feature.
            //http://en.wikipedia.org/wiki/Word_wrap
            string[] words = s.Split(" ".ToCharArray());
            
            int SpaceLeft = LINE_WIDTH;
            int i = 0;
            foreach(string w in words)
            {
                if (w.Length > SpaceLeft)
                {
                    words[i] = "\r\n" + w;//insert line break before item
                    SpaceLeft = LINE_WIDTH - w.Length;
                }
                else
                {
                    SpaceLeft -= (w.Length+1); //1 is for the length of ' '.
                }
                i++;
            }
            return string.Join(" ",words);


            //int[] costTbl = new int[words.Length];
            //Func<int, int, int> cost = (int i, int j) =>
            //                               {
            //                                   int leng = 0;
            //                                   for (int z = i; i < j; i++)
            //                                       leng += words[z].Length;
            //                                   int partialCost = LINE_WIDTH - (i - j) - leng;

            //                                   return partialCost*partialCost;
            //                               };  
        }

        public string Action
        {
            get
            {
                return inputAction.Trim();
            }
        }

        #region ICollection<iMenuItem> Members

        public void Add(iMenuItem item)
        {
            menuItems.Add(item);
        }

        public void Clear()
        {
            menuItems.Clear();
        }

        public bool Contains(iMenuItem item)
        {
            return menuItems.Contains(item);
        }

        void ICollection<iMenuItem>.CopyTo(iMenuItem[] array, int arrayIndex)
        {
            menuItems.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return menuItems.Count; }
        }

        bool ICollection<iMenuItem>.IsReadOnly
        {
            get { return (menuItems as ICollection<iMenuItem>).IsReadOnly; }
        }

        public bool Remove(iMenuItem item)
        {
            return menuItems.Remove(item);
        }

        #endregion

        #region IEnumerable<iMenuItem> Members

        public IEnumerator<iMenuItem> GetEnumerator()
        {
            return menuItems as IEnumerator<iMenuItem>;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return menuItems as IEnumerator;
        }

        #endregion
    }
}
